using System;
using System.Collections.Generic;


namespace HEFramework
{
    /// <summary>
    ///
    /// 资源
    /// 
    /// ----------------------------------------
    /// 作者 hep
    /// 创建时间：2023-03-30 23:27:04
    /// ----------------------------------------
    /// </summary>
    public class Assets : IDisposable
    {
        private class AssetData : IDisposable
        {
            public string AssetBundleName { get; set; }
            public string AssetName { get; set; }
            public string Extension { get; set; }
            public bool IsDone { get; set; }
            public UnityEngine.Object Asset { get; set; }
            public List<Action<UnityEngine.Object>> Callbacks { get; set; } = new();

            public bool IsEquals(string _assetBundleName, string _assetName, string _extension)
            {
                if (AssetBundleName == _assetBundleName && AssetName == _assetName && Extension == _extension)
                {
                    return true;
                }

                return false;
            }

            public void Dispose()
            {
                AssetBundleName = "";
                AssetName = "";
                Extension = "";
                IsDone = false;
                Asset = null;
                Callbacks.Clear();
                ObjectGenerater.Instance.Recycle(this);
            }
        }

        private List<AssetData> waitLoadingAssetDatas = new();
        private List<AssetData> nowLoadingAssetDatas = new();
        private List<AssetData> loadAssetDatas = new();
        private List<AssetData> tempAssetDatas = new();

        public void Update()
        {
            UpdateLoad();
            UpdateWait();
        }

        public void Dispose()
        {
            for (int i = 0; i < waitLoadingAssetDatas.Count; i++)
            {
                waitLoadingAssetDatas[i].Dispose();
            }

            for (int i = 0; i < nowLoadingAssetDatas.Count; i++)
            {
                UnLoadAssetAsync(nowLoadingAssetDatas[i].AssetBundleName);
                nowLoadingAssetDatas[i].Dispose();
            }

            for (int i = 0; i < loadAssetDatas.Count; i++)
            {
                UnLoadAssetAsync(loadAssetDatas[i].AssetBundleName);
                loadAssetDatas[i].Dispose();
            }

            waitLoadingAssetDatas.Clear();
            nowLoadingAssetDatas.Clear();
            loadAssetDatas.Clear();
            ObjectGenerater.Instance.Recycle(this);
            AssetLoader.Instance.RemoveAssets(this);
        }

        /// <summary>
        /// 读取资源（同步）
        /// </summary>
        /// <param name="_assetBundleName">AB包名称</param>
        /// <param name="_assetName">AB包内读取的资源名称</param>
        /// <param name="_extension">读取的资源类型后缀</param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T LoadAssetSyn<T>(string _assetBundleName, string _assetName, string _extension) where T : UnityEngine.Object
        {
            //已加载
            var assetData = GetLoad(_assetBundleName, _assetName, _extension);
            if (assetData != null)
            {
                return (T)assetData.Asset;
            }

            //加载中
            assetData = GetNowLoading(_assetBundleName, _assetName, _extension);
            if (assetData != null)
            {
                nowLoadingAssetDatas.Remove(assetData);
                DoLoadCallback(assetData);
                //异步加载算一次计数，中断使用了同步又算一次，这里使AB计数减一
                UnLoadAssetAsync(_assetBundleName);
                loadAssetDatas.Add(assetData);
                return (T)assetData.Asset;
            }

            //等待中
            assetData = GetWaitLoading(_assetBundleName, _assetName, _extension);
            if (assetData != null)
            {
                waitLoadingAssetDatas.Remove(assetData);
                DoLoadCallback(assetData);
                loadAssetDatas.Add(assetData);
                return (T)assetData.Asset;
            }

            assetData = ObjectGenerater.Instance.Fetch<AssetData>();
            assetData.AssetBundleName = _assetBundleName;
            assetData.AssetName = _assetName;
            assetData.Extension = _extension;
            assetData.Asset = AssetLoader.Instance.LoadAssetSyn<T>(_assetBundleName, _assetName, _extension);
            assetData.IsDone = true;
            loadAssetDatas.Add(assetData);
            return (T)assetData.Asset;
        }


        /// <summary>
        /// 读取资源（异步）
        /// </summary>
        /// <param name="_assetBundleName">AB包名称</param>
        /// <param name="_assetName">AB包内读取的资源名称</param>
        /// <param name="_extension">读取的资源类型后缀</param>
        /// <param name="_callback">数据接收回调函数</param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public void LoadAssetAsync<T>(string _assetBundleName, string _assetName, string _extension, Action<T> _callback) where T : UnityEngine.Object
        {
            if (_callback == null)
            {
                return;
            }

            //已加载
            var assetData = GetLoad(_assetBundleName, _assetName, _extension);
            if (assetData != null)
            {
                _callback((T)assetData.Asset);
                return;
            }

            //加载中
            assetData = GetNowLoading(_assetBundleName, _assetName, _extension);
            if (assetData != null)
            {
                assetData.Callbacks.Add(_ => { _callback((T)_); });
                return;
            }

            //等待中
            assetData = GetWaitLoading(_assetBundleName, _assetName, _extension);
            if (assetData != null)
            {
                assetData.Callbacks.Add(_ => { _callback((T)_); });
                return;
            }


            assetData = ObjectGenerater.Instance.Fetch<AssetData>();
            assetData.AssetBundleName = _assetBundleName;
            assetData.AssetName = _assetName;
            assetData.Extension = _extension;
            assetData.IsDone = false;
            assetData.Callbacks.Add(_ => { _callback((T)_); });

            waitLoadingAssetDatas.Add(assetData);
        }


        private void UpdateWait()
        {
            for (int i = 0; i < waitLoadingAssetDatas.Count; i++)
            {
                tempAssetDatas.Add(waitLoadingAssetDatas[i]);
            }

            for (int i = 0; i < tempAssetDatas.Count; i++)
            {
                DoLoad(tempAssetDatas[i]);
                nowLoadingAssetDatas.Add(tempAssetDatas[i]);
            }

            waitLoadingAssetDatas.Clear();
            tempAssetDatas.Clear();
        }

        private void UpdateLoad()
        {
            for (int i = 0; i < nowLoadingAssetDatas.Count; i++)
            {
                if (nowLoadingAssetDatas[i].IsDone)
                {
                    tempAssetDatas.Add(nowLoadingAssetDatas[i]);
                }
            }

            for (int i = 0; i < tempAssetDatas.Count; i++)
            {
                DoLoadCallback(tempAssetDatas[i]);
                nowLoadingAssetDatas.Remove(tempAssetDatas[i]);
                loadAssetDatas.Add(tempAssetDatas[i]);
            }

            tempAssetDatas.Clear();
        }


        /// <summary>
        /// 卸载资源（异步）
        /// </summary>
        /// <param name="_assetBundleName"></param>
        private void UnLoadAssetAsync(string _assetBundleName)
        {
            AssetLoader.Instance.UnLoadAssetAsync(_assetBundleName);
        }

        private AssetData GetLoad(string _assetBundleName, string _assetName, string _extension)
        {
            for (int i = 0; i < loadAssetDatas.Count; i++)
            {
                if (loadAssetDatas[i].IsEquals(_assetBundleName, _assetName, _extension))
                {
                    return loadAssetDatas[i];
                }
            }

            return null;
        }

        private AssetData GetNowLoading(string _assetBundleName, string _assetName, string _extension)
        {
            for (int i = 0; i < nowLoadingAssetDatas.Count; i++)
            {
                if (nowLoadingAssetDatas[i].IsEquals(_assetBundleName, _assetName, _extension))
                {
                    return nowLoadingAssetDatas[i];
                }
            }

            return null;
        }

        private AssetData GetWaitLoading(string _assetBundleName, string _assetName, string _extension)
        {
            for (int i = 0; i < waitLoadingAssetDatas.Count; i++)
            {
                if (waitLoadingAssetDatas[i].IsEquals(_assetBundleName, _assetName, _extension))
                {
                    return waitLoadingAssetDatas[i];
                }
            }

            return null;
        }


        private void DoLoad(AssetData _data)
        {
            AssetLoader.Instance.LoadAssetAsync<UnityEngine.Object>(_data.AssetBundleName, _data.AssetName, _data.Extension, _ =>
            {
                _data.Asset = _;
                _data.IsDone = true;
            });
        }

        private void DoLoadCallback(AssetData _data)
        {
            //同步强制加载
            if (_data.Asset == null && !_data.IsDone)
            {
                _data.Asset = AssetLoader.Instance.LoadAssetSyn<UnityEngine.Object>(_data.AssetBundleName, _data.AssetName, _data.Extension);
                _data.IsDone = true;
            }

            for (int i = 0; i < _data.Callbacks.Count; i++)
            {
                _data.Callbacks[i].Invoke(_data.Asset);
            }

            _data.Callbacks.Clear();
        }
    }
}